package cn.suimg.shortlink.interceptor;

import cn.suimg.shortlink.request.RequestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;


public class FirewallInterceptor implements HandlerInterceptor {

    /**
     * Logger
     */
    private static final Logger logger = LoggerFactory.getLogger(FirewallInterceptor.class);

    /**
     * 防火墙关键字黑名单列表
     */
    private static final List<String> DANGER_KEYWORD = new ArrayList<String>() {

        /**
         * 重写原因:如果在进行比较的时候回直接执行equals方法而不是String的equalsIgnoreCase
         * 为了统一比较管理需要转换为小写
         * @param o
         * @return
         */
        @Override
        public int indexOf(Object o) {
            if (o instanceof String) {
                return super.indexOf(String.valueOf(o).toLowerCase());
            } else {
                return super.indexOf(o);
            }
        }

        /**
         * 重写原因:在添加元素的时候都转换为小写
         * @param c
         * @return
         */
        @Override
        public boolean addAll(Collection<? extends String> c) {
            Collection<String> newList = new ArrayList<>();
            c.iterator().forEachRemaining(e -> {
                newList.add(e.toLowerCase());
            });
            return super.addAll(newList);
        }

        {
            addAll(Arrays.asList(
                    //其他语言的访问和没必要的后缀
                    "php", "asp", "jsp",
                    //管理员越权
                    "webadmin", "phpmyadmin", "admin",
                    "scripts", "webadmin", "install",
                    //SQL
                    "sqlweb", "pdm",
                    "xampp", "typo3", "thinkphp", "cakephp",
                    "insert","delete","update","select","drop","tables"
            ));
        }
    };

    /**
     * 支持域名白名单 避免别人解析你的IP
     */
    public static final List<String> DOMAIN_NAME_LIST = Arrays.asList("suimg.cn","...");


    /**
     * 需要屏蔽的蜘蛛列表
     */
    public static final List<String> DISABLE_SPIDER_LIST = Arrays.asList("SemrushBot","AhrefsBot","dotbot");

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        StringBuilder mainBuilder = new StringBuilder();
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Entry<String, String[]>> entries = parameterMap.entrySet();
        String currentUrl = request.getRequestURI();
        logger.debug("REQUEST IP:{}", RequestUtil.getIPAddress());
        logger.debug("REQUEST URL:{}",request.getRequestURL().toString());
        logger.debug("METHOD:{}", request.getMethod());
        StringBuffer requestURL = request.getRequestURL();
        //推算出当前域名
        String domainName = requestURL
                .delete(requestURL.length() - request.getRequestURI().length(), requestURL.length())
                .toString()
                .replace("http://","")
                .replace("https://","");
        logger.debug("domainName:{}",domainName);
        //域名验证(经常会有乱解析IP的 web容器无法做域名绑定)
        if(!DOMAIN_NAME_LIST.contains(domainName)){
            return warring(response);
        }

        //屏蔽一些没用的蜘蛛
        String userAgent = request.getHeader("User-Agent");
        for(String spider : DISABLE_SPIDER_LIST){
            if(userAgent.contains(spider)){
                return warring(response);
            }
        }

        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String element = headerNames.nextElement();
            logger.debug("HEADER:{} => {}", element, request.getHeader(element));
        }
        for(String keyword : DANGER_KEYWORD){
            //如果请求的路径中包含敏感信息拦截
            if(currentUrl.contains(keyword)){
                return warring(response);
            }
            //校验所有参数名
            for (Entry<String, String[]> entry : entries) {
                if(entry.getKey().contains(keyword)){
                    return warring(response);
                }
                //校验所有参数值
                String[] values = entry.getValue();
                for (String value : values) {
                    if(value.contains(keyword)){
                        return warring(response);
                    }
                }
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }

    public boolean warring(HttpServletResponse response) throws IOException {
        response.setStatus(403);
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("<!DOCTYPE html><html lang=\"zh-cn\"><head><title>Warring!</title><meta charset=\"utf-8\"><h1>当前请求异常，已经被系统拦截。</h1><h2>The current request exception has been intercepted by the system.</h2></head></html> ");
        return false;
    }


}
